#include <math.h>
#include <stdlib.h>
#include "BigNum.h"

BigNum BigNum_Create()
{
	BigNum BigNum;
	
	BigNum.Top=BigInt_Create();
	BigNum.Bottom=BigInt_Create();
	
	return BigNum;
}

void BigNum_Destroy(BigNum BigNum)
{
	BigInt_Destroy(BigNum.Top);
	BigInt_Destroy(BigNum.Bottom);
}

void BigNum_SetFromInt(BigNum BigNum, int Value)
{
	BigInt_SetFromInt(&BigNum.Top, Value);
	BigInt_SetFromInt(&BigNum.Bottom, 0);
}

void BigNum_SetFromLong(BigNum BigNum, long Value)
{
	BigInt_SetFromLong(&BigNum.Top, Value);
	BigInt_SetFromInt(&BigNum.Bottom, 0);
}

void BigNum_SetFromString(BigNum BigNum, char *Value)
{
	BigInt_SetFromString(&BigNum.Top, Value);
	BigInt_SetFromInt(&BigNum.Bottom, 0);
}

void BigNum_SetTopFromInt(BigNum BigNum, int Value)
{
	BigInt_SetFromInt(&BigNum.Top, Value);
}

void BigNum_SetTopFromLong(BigNum BigNum, long Value)
{
	BigInt_SetFromLong(&BigNum.Top, Value);
}

void BigNum_SetTopFromString(BigNum BigNum, char *Value)
{
	BigInt_SetFromString(&BigNum.Top, Value);
}

void BigNum_SetBottomFromInt(BigNum BigNum, int Value)
{
	BigInt_SetFromInt(&BigNum.Bottom, Value);
}

void BigNum_SetBottomFromLong(BigNum BigNum, long Value)
{
	BigInt_SetFromLong(&BigNum.Bottom, Value);
}

void BigNum_SetBottomFromString(BigNum BigNum, char *Value)
{
	BigInt_SetFromString(&BigNum.Bottom, Value);
}

void BigNum_Add(BigNum Result, BigNum Number0, BigNum Number1)
{
	BigInt Temp0=BigInt_Create();
	BigInt Temp1=BigInt_Create();
	
	BigInt_Mul(&Temp0, Number0.Top, Number1.Bottom);
	BigInt_Mul(&Temp1, Number0.Bottom, Number1.Top);
	BigInt_Add(&Result.Top, Temp0, Temp1);
	
	BigInt_Mul(&Result.Bottom, Number0.Bottom, Number1.Bottom);
	
	BigNum_Reduce(Result);
	
	BigInt_Destroy(Temp0);
	BigInt_Destroy(Temp1);
}

void BigNum_Sub(BigNum Result, BigNum Number0, BigNum Number1)
{
	BigInt Temp0=BigInt_Create();
	BigInt Temp1=BigInt_Create();
	
	BigInt_Mul(&Temp0, Number0.Top, Number1.Bottom);
	BigInt_Mul(&Temp1, Number0.Bottom, Number1.Top);
	BigInt_Sub(&Result.Top, Temp0, Temp1);
	
	BigInt_Mul(&Result.Bottom, Number0.Bottom, Number1.Bottom);
	
	BigNum_Reduce(Result);
	
	BigInt_Destroy(Temp0);
	BigInt_Destroy(Temp1);
}

void BigNum_Mul(BigNum Result, BigNum Number0, BigNum Number1)
{
	BigInt_Mul(&Result.Top, Number0.Top, Number1.Top);
	BigInt_Mul(&Result.Bottom, Number0.Bottom, Number1.Bottom);
	BigNum_Reduce(Result);
}

void BigNum_Div(BigNum Result, BigNum Number0, BigNum Number1)
{
	BigInt_Mul(&Result.Top, Number0.Top, Number1.Bottom);
	BigInt_Mul(&Result.Bottom, Number0.Bottom, Number1.Top);
	BigNum_Reduce(Result);
}

void BigNum_Reduce(BigNum Result)
{
}

void BigNum_SetFromFloat(BigNum BigNum, float Value)
{
	int Divisor=1;
	double Dummy;
	
	while(modf(Value , &Dummy)>0)
	{
		Value*=10;
		++Divisor;
	}
	
	BigInt_SetFromLong(&BigNum.Top, (long) Value);
	BigInt_SetFromInt(&BigNum.Bottom, Divisor);
}

void BigNum_SetFromDouble(BigNum BigNum, double Value)
{
	int Divisor=1;
	double Dummy;
	
	while(modf(Value , &Dummy)>0)
	{
		Value*=10;
		++Divisor;
	}
	
	BigInt_SetFromLong(&BigNum.Top, (long) Value);
	BigInt_SetFromInt(&BigNum.Bottom, Divisor);
}

char *BigNum_GetAsString(BigNum BigNum)
{
	int Precision=10;
	
	BigInt Div=BigInt_Create();
	BigInt_Div(&Div, BigNum.Top, BigNum.Bottom);
	
	int IntegerLength=BigInt_GetDecimalLength(Div);
	char *String=malloc(sizeof(char)*IntegerLength+Precision+2);
	BigInt_GetAsString(Div, String);
	String[IntegerLength]='.';
	String[IntegerLength+1]=0;
	
	return String;
}